home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet internetowy / Rozne / HTTrack 3.40-2 / httrack-3.40-2.exe / {app} / src / htscache.c < prev    next >
C/C++ Source or Header  |  2006-04-09  |  62KB  |  1,742 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. Please visit our Website: http://www.httrack.com
  29. */
  30.  
  31.  
  32. /* ------------------------------------------------------------ */
  33. /* File: httrack.c subroutines:                                 */
  34. /*       cache system (index and stores files in cache)         */
  35. /* Author: Xavier Roche                                         */
  36. /* ------------------------------------------------------------ */
  37.  
  38. /* Internal engine bytecode */
  39. #define HTS_INTERNAL_BYTECODE
  40.  
  41. #include "htscache.h"
  42.  
  43. /* specific definitions */
  44. #include "htsbase.h"
  45. #include "htsbasenet.h"
  46. #include "htsmd5.h"
  47. #include <time.h>
  48.  
  49. #include "htszlib.h"
  50.  
  51.  
  52. #include "htsnostatic.h"
  53. /* END specific definitions */
  54.  
  55. #undef test_flush
  56. #define test_flush if (opt->flush) { fflush(opt->log); fflush(opt->errlog); }
  57.  
  58. // routines de mise en cache
  59.  
  60. /*
  61.   VERSION 1.0 :
  62.   -----------
  63.  
  64. .ndx file
  65.  file with data
  66.    <string>(date/time) [ <string>(hostname+filename) (datfile_position_ascii) ] * number_of_links
  67.  file without data
  68.    <string>(date/time) [ <string>(hostname+filename) (-datfile_position_ascii) ] * number_of_links
  69.  
  70. .dat file
  71.  [ file ] * 
  72. with
  73.   file= (with data)
  74.    [ bytes ] * sizeof(htsblk header) [ bytes ] * n(length of file given in htsblk header)
  75.  file= (without data)
  76.    [ bytes ] * sizeof(htsblk header)
  77. with
  78.  <string>(name) = <length in ascii>+<lf>+<data>
  79.  
  80.  
  81.   VERSION 1.1/1.2 :
  82.   ---------------
  83.  
  84. .ndx file
  85.  file with data
  86.    <string>("CACHE-1.1") <string>(date/time) [ <string>(hostname+filename) (datfile_position_ascii) ] * number_of_links
  87.  file without data
  88.    <string>("CACHE-1.1") <string>(date/time) [ <string>(hostname+filename) (-datfile_position_ascii) ] * number_of_links
  89.  
  90. .dat file
  91.    <string>("CACHE-1.1") [ [Header_1.1] [bytes] * n(length of file given in header) ] *
  92. with
  93.  Header_1.1=
  94.    <int>(statuscode)
  95.    <int>(size)
  96.    <string>(msg)
  97.    <string>(contenttype)
  98.    <string>(charset) [version 3]
  99.    <string>(last-modified)
  100.    <string>(Etag)
  101.    <string>location
  102.    <string>Content-disposition [version 2]
  103.    <string>hostname [version 4]
  104.    <string>URI filename [version 4]
  105.    <string>local filename [version 4]
  106.    [<string>"SD" <string>(supplemental data)]
  107.    [<string>"SD" <string>(supplemental data)]
  108.    ...
  109.    <string>"HTS" (end of header)
  110.    <int>(number of bytes of data) (0 if no data written)
  111. */
  112.  
  113. // Nouveau: si != text/html ne stocke que la taille
  114.  
  115.  
  116. void cache_mayadd(httrackp* opt,cache_back* cache,htsblk* r,char* url_adr,char* url_fil,char* url_save) {
  117.   if ((opt->debug>0) && (opt->log!=NULL)) {
  118.     fspc(opt->log,"debug"); fprintf(opt->log,"File checked by cache: %s"LF,url_adr);
  119.   }            
  120.   // ---stockage en cache---
  121.   // stocker dans le cache?
  122.   if (opt->cache) {
  123.     if (cache_writable(cache)) {
  124.       // ensure not a temporary filename (should not happend ?!)
  125.       if (IS_DELAYED_EXT(url_save)) {
  126.         if (opt->log!=NULL) {
  127.           fspc(opt->log,"warning"); fprintf(opt->log, "aborted cache validation: %s%s still has temporary name %s"LF, url_adr, url_fil, url_save);
  128.         }
  129.         return ;
  130.       }
  131.  
  132.       // c'est le seul endroit ou l'on ajoute des elements dans le cache (fichier entier ou header)
  133.       // on stocke tout fichier "ok", mais Θgalement les rΘponses 404,301,302...
  134.       if (
  135. #if 1
  136.         r->statuscode > 0
  137. #else
  138.         /* We don't store 5XX errors, because it might be a server problem */
  139.         (r->statuscode==200)        /* stocker rΘponse standard, plus */
  140.         || (r->statuscode==204)     /* no content */
  141.         || HTTP_IS_REDIRECT(r->statuscode)    /* redirect */
  142.         || (r->statuscode==401)     /* authorization */
  143.         || (r->statuscode==403)     /* unauthorized */
  144.         || (r->statuscode==404)     /* not found */
  145.         || (r->statuscode==410)     /* gone */
  146. #endif
  147.         )
  148.       {        /* ne pas stocker si la page gΘnΘrΘe est une erreur */
  149.         if (!r->is_file) {
  150.           // stocker fichiers (et robots.txt)
  151.           if ( url_save == NULL || (strnotempty(url_save)) || (strcmp(url_fil,"/robots.txt")==0)) {
  152.             // ajouter le fichier au cache
  153.                         cache_add(cache,*r,url_adr,url_fil,url_save,opt->all_in_cache,opt->path_html);
  154.             //
  155.             // store a reference NOT to redo the same test zillions of times!
  156.             // (problem reported by Lars Clausen)
  157.             // we just store statuscode + location (if any)
  158.             if (url_save == NULL && r->statuscode / 100 >= 3) {
  159.               // cached "fast" header doesn't uet exists
  160.               if (inthash_read((inthash)cache->cached_tests, concat(url_adr, url_fil), NULL) == 0) {
  161.                 char BIGSTK tempo[HTS_URLMAXSIZE*2];
  162.                 sprintf(tempo, "%d", (int)r->statuscode);
  163.                 if (r->location != NULL && r->location[0] != '\0') {
  164.                   strcatbuff(tempo, "\n");
  165.                   strcatbuff(tempo, r->location);
  166.                 }
  167.                 if ((opt->debug>0) && (opt->log!=NULL)) {
  168.                   fspc(opt->log,"debug"); fprintf(opt->log, "Cached fast-header response: %s%s is %d"LF, url_adr, url_fil, (int)r->statuscode);
  169.                 }
  170.                 inthash_add((inthash)cache->cached_tests, concat(url_adr, url_fil), (long int)strdupt(tempo));
  171.               }
  172.             }
  173.           }
  174.         }
  175.       }
  176.     }
  177.   }
  178.   // ---fin stockage en cache---
  179. }
  180.  
  181.  
  182.  
  183. #if 01
  184.  
  185. /* test only - to be removed */
  186.  
  187. #define ZIP_FIELD_STRING(headers, headersSize, field, value) do { \
  188.   if ( (value != NULL) && (value)[0] != '\0') { \
  189.     sprintf(headers + headersSize, "%s: %s\r\n", field, (value != NULL) ? (value) : ""); \
  190.     (headersSize) += (int) strlen(headers + headersSize); \
  191.   } \
  192. } while(0)
  193. #define ZIP_FIELD_INT(headers, headersSize, field, value) do { \
  194.   if ( (value != 0) ) { \
  195.     sprintf(headers + headersSize, "%s: "LLintP"\r\n", field, (LLint)(value)); \
  196.     (headersSize) += (int) strlen(headers + headersSize); \
  197.   } \
  198. } while(0)
  199. #define ZIP_FIELD_INT_FORCE(headers, headersSize, field, value) do { \
  200.   sprintf(headers + headersSize, "%s: "LLintP"\r\n", field, (LLint)(value)); \
  201.   (headersSize) += (int) strlen(headers + headersSize); \
  202. } while(0)
  203.  
  204. struct cache_back_zip_entry {
  205.   unsigned long int hdrPos;
  206.   unsigned long int size;
  207.   int compressionMethod;
  208. };
  209.  
  210. #define ZIP_READFIELD_STRING(line, value, refline, refvalue) do { \
  211.   if (line[0] != '\0' && strfield2(line, refline)) { \
  212.     strcpybuff(refvalue, value); \
  213.     line[0] = '\0'; \
  214.     } \
  215. } while(0)
  216. #define ZIP_READFIELD_INT(line, value, refline, refvalue) do { \
  217.   if (line[0] != '\0' && strfield2(line, refline)) { \
  218.     int intval = 0; \
  219.     sscanf(value, "%d", &intval); \
  220.     (refvalue) = intval; \
  221.     line[0] = '\0'; \
  222.     } \
  223. } while(0)
  224.  
  225.  
  226. /* Ajout d'un fichier en cache */
  227. void cache_add(cache_back* cache,htsblk r,char* url_adr,char* url_fil,char* url_save,int all_in_cache,char* path_prefix) {
  228.   char BIGSTK filename[HTS_URLMAXSIZE*4];
  229.   int dataincache=0;    // put data in cache ?
  230.   char BIGSTK headers[8192];
  231.   int headersSize = 0;
  232.   int entryBodySize = 0;
  233.   int entryFilenameSize = 0;
  234.   zip_fileinfo fi;
  235.     char* url_save_suffix = url_save;
  236.     int zErr;
  237.  
  238.   // robots.txt hack
  239.   if (url_save == NULL) {
  240.     dataincache=0;        // testing links
  241.   }
  242.   else {
  243.     if ( (strnotempty(url_save)==0) ) {
  244.       if (strcmp(url_fil,"/robots.txt")==0)        // robots.txt
  245.         dataincache=1;
  246.       else
  247.         return;   // error (except robots.txt)
  248.     }
  249.  
  250.     /* Data in cache ? */
  251.     if (is_hypertext_mime(r.contenttype, url_fil)
  252.             || (may_be_hypertext_mime(r.contenttype, url_fil) && r.adr != NULL)
  253.             )
  254.         {
  255.       dataincache=1;
  256.         } else if (all_in_cache) {
  257.       dataincache=1;
  258.         }
  259.   }
  260.  
  261.   if (r.size < 0)   // error
  262.     return;
  263.  
  264.   // data in cache
  265.   if (dataincache) {
  266.     assertf(((int) r.size) == r.size);
  267.     entryBodySize = (int) r.size;
  268.   }
  269.  
  270.   /* Fields */
  271.   headers[0] = '\0';
  272.   headersSize = 0;
  273.   /* */
  274.   {
  275.     char* message;
  276.     if (strlen(r.msg) < 32) {
  277.       message = r.msg;
  278.     } else {
  279.       message = "(See X-StatusMessage)";
  280.     }
  281.     /* 64 characters MAX for first line */
  282.     sprintf(headers + headersSize, "HTTP/1.%c %d %s\r\n", '1', r.statuscode, r.msg);
  283.   }
  284.   headersSize += (int) strlen(headers + headersSize);
  285.  
  286.     if (path_prefix != NULL && path_prefix[0] != '\0' && url_save != NULL && url_save[0] != '\0') {
  287.         int prefixLen = (int) strlen(path_prefix);
  288.         if (strncmp(url_save, path_prefix, prefixLen) == 0) {
  289.             url_save_suffix += prefixLen;
  290.         }
  291.     }
  292.  
  293.   /* Second line MUST ALWAYS be X-In-Cache */
  294.   ZIP_FIELD_INT_FORCE(headers, headersSize, "X-In-Cache", dataincache);
  295.   ZIP_FIELD_INT(headers, headersSize, "X-StatusCode", r.statuscode);
  296.   ZIP_FIELD_STRING(headers, headersSize, "X-StatusMessage", r.msg);
  297.   ZIP_FIELD_INT(headers, headersSize, "X-Size", r.size);           // size
  298.   ZIP_FIELD_STRING(headers, headersSize, "Content-Type", r.contenttype);      // contenttype
  299.   ZIP_FIELD_STRING(headers, headersSize, "X-Charset", r.charset);          // contenttype
  300.   ZIP_FIELD_STRING(headers, headersSize, "Last-Modified", r.lastmodified);     // last-modified
  301.   ZIP_FIELD_STRING(headers, headersSize, "Etag", r.etag);             // Etag
  302.   ZIP_FIELD_STRING(headers, headersSize, "Location", r.location);         // 'location' pour moved
  303.   ZIP_FIELD_STRING(headers, headersSize, "Content-Disposition", r.cdispo);           // Content-disposition
  304.   ZIP_FIELD_STRING(headers, headersSize, "X-Addr", url_adr);            // Original address
  305.   ZIP_FIELD_STRING(headers, headersSize, "X-Fil", url_fil);            // Original URI filename
  306.   ZIP_FIELD_STRING(headers, headersSize, "X-Save", url_save_suffix);           // Original save filename
  307.   
  308.   entryFilenameSize = (int) ( strlen(url_adr) + strlen(url_fil));
  309.   
  310.   /* Filename */
  311.   if (!link_has_authority(url_adr)) {
  312.     strcpybuff(filename, "http://");
  313.   } else {
  314.     strcpybuff(filename, "");
  315.   }
  316.   strcatbuff(filename, url_adr);
  317.   strcatbuff(filename, url_fil);
  318.  
  319.   /* Time */
  320.   memset(&fi, 0, sizeof(fi));
  321.   if (r.lastmodified[0] != '\0') {
  322.     struct tm* tm_s=convert_time_rfc822(r.lastmodified);
  323.     if (tm_s) {
  324.       fi.tmz_date.tm_sec = (uInt) tm_s->tm_sec;
  325.       fi.tmz_date.tm_min = (uInt) tm_s->tm_min;
  326.       fi.tmz_date.tm_hour = (uInt) tm_s->tm_hour;
  327.       fi.tmz_date.tm_mday = (uInt) tm_s->tm_mday;
  328.       fi.tmz_date.tm_mon = (uInt) tm_s->tm_mon;
  329.       fi.tmz_date.tm_year = (uInt) tm_s->tm_year;
  330.     }
  331.   }
  332.   
  333.   /* Open file - NOTE: headers in "comment" */
  334.   if ((zErr = zipOpenNewFileInZip((zipFile) cache->zipOutput,
  335.     filename,
  336.     &fi,
  337.     /* 
  338.     Store headers in realtime in the local file directory as extra field
  339.     In case of crash, we'll be able to recover the whole ZIP file by rescanning it
  340.     */
  341.     headers,
  342.     (uInt) strlen(headers),
  343.     NULL,
  344.     0,
  345.     NULL, /* comment */
  346.     Z_DEFLATED,
  347.     Z_DEFAULT_COMPRESSION)) != Z_OK)
  348.   {
  349.     int zip_zipOpenNewFileInZip_failed = 0;
  350.     assertf(zip_zipOpenNewFileInZip_failed);
  351.   }
  352.   
  353.   /* Write data in cache */
  354.   if (dataincache) {
  355.     if (r.is_write == 0) {
  356.       if (r.size > 0 && r.adr != NULL) {
  357.         if ((zErr = zipWriteInFileInZip((zipFile) cache->zipOutput, r.adr, (int) r.size)) != Z_OK) {
  358.           int zip_zipWriteInFileInZip_failed = 0;
  359.           assertf(zip_zipWriteInFileInZip_failed);
  360.         }
  361.       }
  362.     } else {
  363.       FILE* fp;
  364.       // On recopie le fichier..
  365.       LLint file_size=fsize(fconv(url_save));
  366.       if (file_size>=0) {
  367.         fp=fopen(fconv(url_save),"rb");
  368.         if (fp!=NULL) {
  369.           char BIGSTK buff[32768];
  370.           INTsys nl;
  371.           do {
  372.             nl=fread(buff,1,32768,fp);
  373.             if (nl>0) { 
  374.               if ((zErr = zipWriteInFileInZip((zipFile) cache->zipOutput, buff, (int) nl)) != Z_OK) {
  375.                 int zip_zipWriteInFileInZip_failed = 0;
  376.                 assertf(zip_zipWriteInFileInZip_failed);
  377.               }
  378.             }
  379.           } while(nl>0);
  380.           fclose(fp);
  381.         } else {
  382.           /* Err FIXME - lost file */
  383.         }
  384.       } /* Empty files are OK */
  385.     }
  386.   }
  387.   
  388.   /* Close */
  389.   if ((zErr = zipCloseFileInZip((zipFile) cache->zipOutput)) != Z_OK) {
  390.     int zip_zipCloseFileInZip_failed = 0;
  391.     assertf(zip_zipCloseFileInZip_failed);
  392.   }
  393.  
  394.   /* Flush */
  395.   if ((zErr = zipFlush((zipFile) cache->zipOutput)) != 0) {
  396.     int zip_zipFlush_failed = 0;
  397.     assertf(zip_zipFlush_failed);
  398.   }
  399. }
  400.  
  401. #else
  402.  
  403. /* Ajout d'un fichier en cache */
  404. void cache_add(cache_back* cache,htsblk r,char* url_adr,char* url_fil,char* url_save,int all_in_cache) {
  405.   int pos;
  406.   char s[256];
  407.   char BIGSTK buff[HTS_URLMAXSIZE*4];
  408.   int ok=1;
  409.   int dataincache=0;    // donnΘe en cache?
  410.   FILE* cache_ndx = cache->ndx;
  411.   FILE* cache_dat = cache->dat;
  412.   /*char digest[32+2];*/
  413.   /*digest[0]='\0';*/
  414.  
  415.   // Longueur url_save==0?
  416.   if ( (strnotempty(url_save)==0) ) {
  417.     if (strcmp(url_fil,"/robots.txt")==0)        // robots.txt
  418.       dataincache=1;
  419.     else if (strcmp(url_fil,"/test")==0)        // testing links
  420.       dataincache=0;
  421.     else
  422.       return;   // erreur (sauf robots.txt)
  423.   }
  424.  
  425.   if (r.size <= 0)   // taille <= 0 
  426.     return;          // refusΘ..
  427.  
  428.   // Mettre les *donΘes* en cache ?
  429.   if (is_hypertext_mime(r.contenttype, url_fil))    // html, mise en cache des donnΘes et 
  430.     dataincache=1;                               // pas uniquement de l'en tΩte
  431.   else if (all_in_cache)
  432.     dataincache=1;                               // forcer tout en cache
  433.  
  434.   /* calcul md5 ? */
  435.   /*
  436.   if (is_hypertext_mime(r.contenttype)) {    // html, calcul MD5
  437.     if (r.adr) {
  438.       domd5mem(r.adr,r.size,digest,1);
  439.     }
  440.   }*/
  441.  
  442.   // Position
  443.   fflush(cache_dat); fflush(cache_ndx);
  444.   pos=ftell(cache_dat);
  445.   // Θcrire pointeur seek, adresse, fichier
  446.   if (dataincache)   // patcher
  447.     sprintf(s,"%d\n",pos);    // ecrire tel que (eh oui Θvite les \0..)
  448.   else
  449.     sprintf(s,"%d\n",-pos);   // ecrire tel que (eh oui Θvite les \0..)
  450.  
  451.   // data
  452.   // Θcrire donnΘes en-tΩte, donnΘes fichier
  453.   /*if (!dataincache) {   // patcher
  454.     r.size=-r.size;  // nΘgatif
  455.   }*/
  456.  
  457.   // Construction header
  458.   ok=0;
  459.   if (cache_wint(cache_dat,r.statuscode) != -1       // statuscode
  460.   && cache_wLLint(cache_dat,r.size) != -1           // size
  461.   && cache_wstr(cache_dat,r.msg) != -1              // msg
  462.   && cache_wstr(cache_dat,r.contenttype) != -1      // contenttype
  463.   && cache_wstr(cache_dat,r.charset) != -1          // contenttype
  464.   && cache_wstr(cache_dat,r.lastmodified) != -1     // last-modified
  465.   && cache_wstr(cache_dat,r.etag) != -1             // Etag
  466.   && cache_wstr(cache_dat,(r.location!=NULL)?r.location:"") != -1         // 'location' pour moved
  467.   && cache_wstr(cache_dat,r.cdispo) != -1           // Content-disposition
  468.   && cache_wstr(cache_dat,url_adr) != -1            // Original address
  469.   && cache_wstr(cache_dat,url_fil) != -1            // Original URI filename
  470.   && cache_wstr(cache_dat,url_save) != -1           // Original save filename
  471.   && cache_wstr(cache_dat,r.headers) != -1          // Full HTTP Headers
  472.   && cache_wstr(cache_dat,"HTS") != -1              // end of header
  473.   ) {
  474.     ok=1;       /* ok */
  475.   }
  476.   // Fin construction header
  477.  
  478.   /*if ((int) fwrite((char*) &r,1,sizeof(htsblk),cache_dat) == sizeof(htsblk)) {*/
  479.   if (ok) {
  480.     if (dataincache) {    // mise en cache?
  481.       if (!r.adr) {       /* taille nulle (parfois en cas de 301 */
  482.         if (cache_wLLint(cache_dat,0)==-1)          /* 0 bytes */
  483.           ok=0;
  484.       } else if (r.is_write==0) {  // en mΘmoire, recopie directe
  485.         if (cache_wLLint(cache_dat,r.size)!=-1) {
  486.           if (r.size>0) {   // taille>0
  487.             if (fwrite(r.adr,1,(INTsys)r.size,cache_dat)!=r.size)
  488.               ok=0;
  489.           } else    // taille=0, ne rien Θcrire
  490.             ok=0;
  491.         } else
  492.           ok=0;
  493.       } else {  // recopier fichier dans cache
  494.         FILE* fp;
  495.         // On recopie le fichier..
  496.         LLint file_size=fsize(fconv(url_save));
  497.         if (file_size>=0) {
  498.           if (cache_wLLint(cache_dat,file_size)!=-1) {
  499.             fp=fopen(fconv(url_save),"rb");
  500.             if (fp!=NULL) {
  501.               char BIGSTK buff[32768];
  502.               INTsys nl;
  503.               do {
  504.                 nl=fread(buff,1,32768,fp);
  505.                 if (nl>0) { 
  506.                   if ((INTsys)fwrite(buff,1,(INTsys)nl,cache_dat)!=nl) {  // erreur
  507.                     nl=-1;
  508.                     ok=0;
  509.                   }
  510.                 }
  511.               } while(nl>0);
  512.               fclose(fp);
  513.             } else ok=0;
  514.           } else ok=0;
  515.         } else ok=0;
  516.       }
  517.     } else {
  518.       if (cache_wLLint(cache_dat,0)==-1)          /* 0 bytes */
  519.         ok=0;
  520.     }
  521.   } else ok=0;
  522.   /*if (!dataincache) {   // dΘpatcher
  523.     r.size=-r.size;
  524.   }*/
  525.  
  526.   // index
  527.   // adresse+cr+fichier+cr
  528.   if (ok) {
  529.     buff[0]='\0'; strcatbuff(buff,url_adr); strcatbuff(buff,"\n"); strcatbuff(buff,url_fil); strcatbuff(buff,"\n");
  530.     cache_wstr(cache_ndx,buff);
  531.     fwrite(s,1,strlen(s),cache_ndx);
  532.   }  // si ok=0 on a peut Ωtre Θcrit des donnΘes pour rien mais on s'en tape
  533.   
  534.   // en cas de plantage, on aura au moins le cache!
  535.   fflush(cache_dat); fflush(cache_ndx);
  536. }
  537.  
  538. #endif
  539.  
  540.  
  541. htsblk cache_read(httrackp* opt,cache_back* cache,char* adr,char* fil,char* save,char* location) {
  542.   return cache_readex(opt,cache,adr,fil,save,location,NULL,0);
  543. }
  544.  
  545. htsblk cache_read_ro(httrackp* opt,cache_back* cache,char* adr,char* fil,char* save,char* location) {
  546.   return cache_readex(opt,cache,adr,fil,save,location,NULL,1);
  547. }
  548.  
  549. static htsblk cache_readex_old(httrackp* opt,cache_back* cache,char* adr,char* fil,char* save,char* location,
  550.                                char* return_save, int readonly);
  551.  
  552. static htsblk cache_readex_new(httrackp* opt,cache_back* cache,char* adr,char* fil,char* save,char* location,
  553.                                char* return_save, int readonly);
  554.  
  555. // lecture d'un fichier dans le cache
  556. // si save==null alors test unqiquement
  557. htsblk cache_readex(httrackp* opt,cache_back* cache,char* adr,char* fil,char* save,char* location,
  558.                     char* return_save, int readonly) {
  559.   if (cache->zipInput != NULL) {
  560.     return cache_readex_new(opt, cache, adr, fil, save, location, return_save, readonly);
  561.   } else {
  562.     return cache_readex_old(opt, cache, adr, fil, save, location, return_save, readonly);
  563.   }
  564. }
  565.  
  566. // lecture d'un fichier dans le cache
  567. // si save==null alors test unqiquement
  568. static htsblk cache_readex_new(httrackp* opt,cache_back* cache,char* adr,char* fil,char* save,char* location,
  569.                                char* return_save, int readonly) {
  570.   char BIGSTK location_default[HTS_URLMAXSIZE*2];
  571.   char BIGSTK buff[HTS_URLMAXSIZE*2];
  572.   char BIGSTK previous_save[HTS_URLMAXSIZE*2];
  573.   char BIGSTK previous_save_[HTS_URLMAXSIZE*2];
  574.   long int hash_pos;
  575.   int hash_pos_return;
  576.   htsblk r;
  577.   memset(&r, 0, sizeof(htsblk)); r.soc=INVALID_SOCKET;
  578.     location_default[0] = '\0';
  579.     previous_save[0] = previous_save_[0] = '\0';
  580.  
  581.   if (location) {
  582.     r.location = location;
  583.   } else {
  584.     r.location = location_default;
  585.   }
  586.   strcpybuff(r.location, ""); 
  587.   strcpybuff(buff, adr);
  588.   strcatbuff(buff,fil);
  589.   hash_pos_return = inthash_read((inthash)cache->hashtable, buff, (long int*)&hash_pos);
  590.   /* avoid errors on data entries */
  591.   if (adr[0] == '/' && adr[1] == '/' && adr[2] == '[') {
  592. #if HTS_FAST_CACHE
  593.     hash_pos_return = 0;
  594. #else
  595.     a = NULL;
  596. #endif
  597.   }
  598.  
  599.   if (hash_pos_return) {
  600.     uLong posInZip;
  601.     if (hash_pos > 0) {
  602.       posInZip = (uLong) hash_pos;
  603.     } else {
  604.       posInZip = (uLong) -hash_pos;
  605.     }
  606.     if (unzSetOffset((unzFile) cache->zipInput, posInZip) == Z_OK) {
  607.       /* Read header (Max 8KiB) */
  608.       if (unzOpenCurrentFile((unzFile) cache->zipInput) == Z_OK) {
  609.         char BIGSTK headerBuff[8192 + 2];
  610.         int readSizeHeader;
  611.         int totalHeader = 0;
  612.         int dataincache = 0;
  613.         
  614.         /* For BIG comments */
  615.         headerBuff[0] 
  616.           = headerBuff[sizeof(headerBuff) - 1] 
  617.           = headerBuff[sizeof(headerBuff) - 2] 
  618.           = headerBuff[sizeof(headerBuff) - 3] = '\0';
  619.  
  620.         if ( (readSizeHeader = unzGetLocalExtrafield((unzFile) cache->zipInput, headerBuff, sizeof(headerBuff) - 2)) > 0) 
  621.         /*if (unzGetCurrentFileInfo((unzFile) cache->zipInput, NULL,
  622.           NULL, 0, NULL, 0, headerBuff, sizeof(headerBuff) - 2) == Z_OK ) */
  623.         {
  624.           int offset = 0;
  625.           char BIGSTK line[HTS_URLMAXSIZE + 2];
  626.           int lineEof = 0;
  627.           /*readSizeHeader = (int) strlen(headerBuff);*/
  628.           headerBuff[readSizeHeader] = '\0';
  629.           do {
  630.             char* value;
  631.             line[0] = '\0';
  632.             offset += binput(headerBuff + offset, line, sizeof(line) - 2);
  633.             if (line[0] == '\0') {
  634.               lineEof = 1;
  635.             }
  636.             value = strchr(line, ':');
  637.             if (value != NULL) {
  638.               *value++ = '\0';
  639.               if (*value == ' ' || *value == '\t') value++;
  640.               ZIP_READFIELD_INT(line, value, "X-In-Cache", dataincache);
  641.               ZIP_READFIELD_INT(line, value, "X-Statuscode", r.statuscode);
  642.               ZIP_READFIELD_STRING(line, value, "X-StatusMessage", r.msg);              // msg
  643.               ZIP_READFIELD_INT(line, value, "X-Size", r.size);           // size
  644.               ZIP_READFIELD_STRING(line, value, "Content-Type", r.contenttype);      // contenttype
  645.               ZIP_READFIELD_STRING(line, value, "X-Charset", r.charset);          // contenttype
  646.               ZIP_READFIELD_STRING(line, value, "Last-Modified", r.lastmodified);     // last-modified
  647.               ZIP_READFIELD_STRING(line, value, "Etag", r.etag);             // Etag
  648.               ZIP_READFIELD_STRING(line, value, "Location", r.location);         // 'location' pour moved
  649.               ZIP_READFIELD_STRING(line, value, "Content-Disposition", r.cdispo);           // Content-disposition
  650.               //ZIP_READFIELD_STRING(line, value, "X-Addr", ..);            // Original address
  651.               //ZIP_READFIELD_STRING(line, value, "X-Fil", ..);            // Original URI filename
  652.               ZIP_READFIELD_STRING(line, value, "X-Save", previous_save_);           // Original save filename
  653.             }
  654.           } while(offset < readSizeHeader && !lineEof);
  655.           totalHeader = offset;
  656.  
  657.                     /* Previous entry */
  658.                     if (previous_save_[0] != '\0') {
  659.                         int pathLen = (int) strlen(opt->path_html);
  660.                         if (pathLen != 0 && strncmp(previous_save_, opt->path_html, pathLen) != 0) {            // old (<3.40) buggy format
  661.                             sprintf(previous_save, "%s%s", opt->path_html, previous_save_);
  662.                         } else {
  663.                             strcpy(previous_save, previous_save_);
  664.                         }
  665.                     }
  666.           if (return_save != NULL) {
  667.             strcpybuff(return_save, previous_save);
  668.           }
  669.  
  670.           /* Complete fields */
  671.           r.totalsize=r.size;
  672.           r.adr=NULL;
  673.           r.out=NULL;
  674.           r.fp=NULL;
  675.           
  676.           if (save != NULL) {     /* ne pas lire uniquement header */
  677.             int ok = 0;
  678.                        
  679. #if HTS_DIRECTDISK
  680.             // Court-circuit:
  681.             // Peut-on stocker le fichier directement sur disque?
  682.             if (ok) {
  683.               if (r.msg[0] == '\0') {
  684.                 strcpybuff(r.msg,"Cache Read Error : Unexpected error");
  685.               }
  686.             }
  687.             else if (!readonly && r.statuscode==200 && !is_hypertext_mime(r.contenttype, fil) && strnotempty(save)) {    // pas HTML, Θcrire sur disk directement
  688.               
  689.               r.is_write=1;    // Θcrire
  690.                             if (!dataincache) {
  691.                                 if (fexist(fconv(save))) {  // un fichier existe dΘja
  692.                                     //if (fsize(fconv(save))==r.size) {  // mΩme taille -- NON tant pis (taille mal declaree)
  693.                                     ok=1;    // plus rien α faire
  694.                                     filenote(save,NULL);        // noter comme connu
  695.                                     file_notify(adr, fil, save, 0, 0, 1);        // data in cache
  696.                                 }
  697.                             }
  698.               
  699.               if (!dataincache && !ok) { // Pas de donnΘe en cache et fichier introuvable : erreur!
  700.                 if (opt->norecatch) {
  701.                   file_notify(adr, fil, save, 1, 0, 0);
  702.                   filecreateempty(save);
  703.                   //
  704.                   r.statuscode=STATUSCODE_INVALID;
  705.                   strcpybuff(r.msg,"File deleted by user not recaught");
  706.                   ok=1;     // ne pas rΘcupΘrer (et pas d'erreur)
  707.                 } else {
  708.                   file_notify(adr, fil, save, 1, 1, 0);
  709.                   r.statuscode=STATUSCODE_INVALID;
  710.                   strcpybuff(r.msg,"Previous cache file not found");
  711.                   ok=1;    // ne pas rΘcupΘrer
  712.                 }
  713.               }
  714.               
  715.               if (!ok) {        // load from cache
  716.                 file_notify(adr, fil, save, 1, 1, 1);        // data in cache
  717.                 r.out=filecreate(save);
  718. #if HDEBUG
  719.                 printf("direct-disk: %s\n",save);
  720. #endif
  721.                 if (r.out!=NULL) {
  722.                   char BIGSTK buff[32768+4];
  723.                   LLint size = r.size;
  724.                   if (size > 0) {
  725.                     INTsys nl;
  726.                     do {
  727.                       nl = unzReadCurrentFile((unzFile) cache->zipInput, buff, (int)minimum(size, 32768));
  728.                       if (nl>0) {
  729.                         size-=nl; 
  730.                         if ((INTsys)fwrite(buff,1,(INTsys)nl,r.out)!=nl) {  // erreur
  731.                           r.statuscode=STATUSCODE_INVALID;
  732.                           sprintf(r.msg,"Cache Read Error : Read To Disk: %s", strerror(errno));
  733.                         }
  734.                       }
  735.                     } while((nl>0) && (size>0) && (r.statuscode!=-1));
  736.                   }
  737.                   
  738.                   fclose(r.out);
  739.                   r.out=NULL;
  740. #if HTS_WIN==0
  741.                   chmod(save,HTS_ACCESS_FILE);      
  742. #endif          
  743.                 } else {
  744.                   r.statuscode=STATUSCODE_INVALID;
  745.                   strcpybuff(r.msg,"Cache Write Error : Unable to Create File");
  746.                   //printf("%s\n",save);
  747.                 }
  748.               }
  749.               
  750.             } else
  751. #endif
  752.             { // lire en mΘmoire
  753.               
  754.               if (!dataincache) {
  755.                 if (strnotempty(save)) { // Pas de donnΘe en cache, bizarre car html!!!
  756.                   r.statuscode=STATUSCODE_INVALID;
  757.                   strcpybuff(r.msg,"Previous cache file not found (2)");
  758.                 } else {                 /* Read in memory from cache */
  759.                   if (strnotempty(previous_save) && fexist(previous_save)) {
  760.                     FILE* fp = fopen(fconv(previous_save), "rb");
  761.                     if (fp != NULL) {
  762.                       r.adr=(char*) malloct((INTsys)r.size + 4);
  763.                       if (r.adr != NULL) {
  764.                         if (r.size > 0 && fread(r.adr, 1, (INTsys) r.size, fp) != r.size) {
  765.                           r.statuscode=STATUSCODE_INVALID;
  766.                           sprintf(r.msg,"Read error in cache disk data: %s", strerror(errno));
  767.                         }
  768.                       } else {
  769.                         r.statuscode=STATUSCODE_INVALID;
  770.                         strcpybuff(r.msg,"Read error (memory exhausted) from cache");
  771.                       }
  772.                       fclose(fp);
  773.                     }
  774.                   } else {
  775.                     r.statuscode=STATUSCODE_INVALID;
  776.                     strcpybuff(r.msg,"Cache file not found on disk");
  777.                   }
  778.                 }
  779.               } else {
  780.                 // lire fichier (d'un coup)
  781.                 r.adr=(char*) malloct((INTsys)r.size+4);
  782.                 if (r.adr!=NULL) {
  783.                   if (unzReadCurrentFile((unzFile) cache->zipInput, r.adr, (INTsys)r.size) != r.size) {  // erreur
  784.                     freet(r.adr);
  785.                     r.adr=NULL;
  786.                     r.statuscode=STATUSCODE_INVALID;
  787.                     strcpybuff(r.msg,"Cache Read Error : Read Data");
  788.                   } else
  789.                     *(r.adr+r.size)='\0';
  790.                   //printf(">%s status %d\n",back[p].r.contenttype,back[p].r.statuscode);
  791.                 } else {  // erreur
  792.                   r.statuscode=STATUSCODE_INVALID;
  793.                   strcpybuff(r.msg,"Cache Memory Error");
  794.                 }
  795.               }
  796.             }
  797.           }    // si save==null, ne rien charger (juste en tΩte)
  798.  
  799.  
  800.         } else {
  801.           r.statuscode=STATUSCODE_INVALID;
  802.           strcpybuff(r.msg,"Cache Read Error : Read Header Data");
  803.         }
  804.         unzCloseCurrentFile((unzFile) cache->zipInput);
  805.       } else {
  806.         r.statuscode=STATUSCODE_INVALID;
  807.         strcpybuff(r.msg,"Cache Read Error : Open File");
  808.       }
  809.  
  810.     } else {
  811.       r.statuscode=STATUSCODE_INVALID;
  812.       strcpybuff(r.msg,"Cache Read Error : Bad Offset");
  813.     }
  814.   } else {
  815.     r.statuscode=STATUSCODE_INVALID;
  816.     strcpybuff(r.msg,"File Cache Entry Not Found");
  817.   }
  818.   if (!location) {   /* don't export internal buffer */
  819.     r.location = NULL;
  820.   }
  821.   return r;
  822. }
  823.  
  824.  
  825. // lecture d'un fichier dans le cache
  826. // si save==null alors test unqiquement
  827. static htsblk cache_readex_old(httrackp* opt,cache_back* cache,char* adr,char* fil,char* save,char* location,
  828.                                char* return_save, int readonly) {
  829. #if HTS_FAST_CACHE
  830.   long int hash_pos;
  831.   int hash_pos_return;
  832. #else
  833.   char* a;
  834. #endif
  835.   char BIGSTK buff[HTS_URLMAXSIZE*2];
  836.   char BIGSTK location_default[HTS_URLMAXSIZE*2];
  837.   char BIGSTK previous_save[HTS_URLMAXSIZE*2];
  838.   htsblk r;
  839.   int ok=0;
  840.   int header_only=0;
  841.  
  842.   memset(&r, 0, sizeof(htsblk)); r.soc=INVALID_SOCKET;
  843.   if (location) {
  844.     r.location = location;
  845.   } else {
  846.     r.location = location_default;
  847.   }
  848.   strcpybuff(r.location, ""); 
  849. #if HTS_FAST_CACHE
  850.   strcpybuff(buff,adr); strcatbuff(buff,fil);
  851.   hash_pos_return=inthash_read((inthash)cache->hashtable,buff,(long int*)&hash_pos);
  852. #else
  853.   buff[0]='\0'; strcatbuff(buff,"\n"); strcatbuff(buff,adr); strcatbuff(buff,"\n"); strcatbuff(buff,fil); strcatbuff(buff,"\n");
  854.   if (cache->use)
  855.     a=strstr(cache->use,buff);
  856.   else
  857.     a=NULL;       // forcer erreur
  858. #endif
  859.  
  860.   /* avoid errors on data entries */
  861.   if (adr[0] == '/' && adr[1] == '/' && adr[2] == '[') {
  862. #if HTS_FAST_CACHE
  863.     hash_pos_return = 0;
  864. #else
  865.     a = NULL;
  866. #endif
  867.   }
  868.  
  869.   // en cas de succΦs
  870. #if HTS_FAST_CACHE
  871.   if (hash_pos_return) {
  872. #else
  873.   if (a!=NULL) {  // OK existe en cache!
  874. #endif
  875.     INTsys pos;
  876. #if DEBUGCA
  877.     fprintf(stdout,"..cache: %s%s at ",adr,fil);
  878. #endif
  879.     
  880. #if HTS_FAST_CACHE
  881.     pos=hash_pos;     /* simply */
  882. #else
  883.     a+=strlen(buff);
  884.     sscanf(a,"%d",&pos);    // lire position
  885. #endif
  886. #if DEBUGCA
  887.     printf("%d\n",pos);
  888. #endif
  889.  
  890.     fflush(cache->olddat); 
  891.     if (fseek(cache->olddat,((pos>0)?pos:(-pos)),SEEK_SET) == 0) {
  892.       /* Importer cache1.0 */
  893.       if (cache->version==0) {
  894.         OLD_htsblk old_r;
  895.         if (fread((char*) &old_r,1,sizeof(old_r),cache->olddat)==sizeof(old_r)) { // lire tout (y compris statuscode etc)
  896.           r.statuscode=old_r.statuscode;
  897.           r.size=old_r.size;        // taille fichier
  898.           strcpybuff(r.msg,old_r.msg);
  899.           strcpybuff(r.contenttype,old_r.contenttype);
  900.           ok=1;     /* import  ok */
  901.         }
  902.       /* */
  903.       /* Cache 1.1 */
  904.       } else {
  905.         char check[256];
  906.         LLint size_read;
  907.         check[0]='\0';
  908.         //
  909.         cache_rint(cache->olddat,&r.statuscode);
  910.         cache_rLLint(cache->olddat,&r.size);
  911.         cache_rstr(cache->olddat,r.msg);
  912.         cache_rstr(cache->olddat,r.contenttype);
  913.         if (cache->version >= 3)
  914.           cache_rstr(cache->olddat,r.charset);
  915.         cache_rstr(cache->olddat,r.lastmodified);
  916.         cache_rstr(cache->olddat,r.etag);
  917.         cache_rstr(cache->olddat,r.location);
  918.         if (cache->version >= 2)
  919.           cache_rstr(cache->olddat,r.cdispo);
  920.         if (cache->version >= 4) {
  921.           cache_rstr(cache->olddat, previous_save);  // adr
  922.           cache_rstr(cache->olddat, previous_save);  // fil
  923.           previous_save[0] = '\0';
  924.           cache_rstr(cache->olddat, previous_save);  // save
  925.           if (return_save != NULL) {
  926.             strcpybuff(return_save, previous_save);
  927.           }
  928.         }
  929.         if (cache->version >= 5) {
  930.           r.headers = cache_rstr_addr(cache->olddat);
  931.         }
  932.         //
  933.         cache_rstr(cache->olddat,check);
  934.         if (strcmp(check,"HTS")==0) {           /* intΘgritΘ OK */
  935.           ok=1;
  936.         }
  937.         cache_rLLint(cache->olddat,&size_read);       /* lire size pour Ωtre s√r de la taille dΘclarΘe (rΘΘcrire) */
  938.         if (size_read>0) {                         /* si inscrite ici */
  939.           r.size=size_read;
  940.         } else {                              /* pas de donnΘes directement dans le cache, fichier prΘsent? */
  941.           if (r.statuscode!=200)
  942.             header_only=1;          /* que l'en tΩte ici! */
  943.         }
  944.       }
  945.  
  946.       /* Remplir certains champs */
  947.       r.totalsize=r.size;
  948.  
  949.       // lecture du header (y compris le statuscode)
  950.       /*if (fread((char*) &r,1,sizeof(htsblk),cache->olddat)==sizeof(htsblk)) { // lire tout (y compris statuscode etc)*/
  951.       if (ok) {
  952.         // sΘcuritΘ
  953.         r.adr=NULL;
  954.         r.out=NULL;
  955.         ////r.location=NULL;  non, fixΘe lors des 301 ou 302
  956.         r.fp=NULL;
  957.         
  958.         if ( (r.statuscode>=0) && (r.statuscode<=999)
  959.           && (r.notmodified>=0)  && (r.notmodified<=9) ) {   // petite vΘrif intΘgritΘ
  960.           if ((save) && (!header_only) ) {     /* ne pas lire uniquement header */
  961.             //int to_file=0;
  962.             
  963.             r.adr=NULL; r.soc=INVALID_SOCKET; 
  964.             // // r.location=NULL;
  965.             
  966. #if HTS_DIRECTDISK
  967.             // Court-circuit:
  968.             // Peut-on stocker le fichier directement sur disque?
  969.             if (!readonly && r.statuscode==200 && !is_hypertext_mime(r.contenttype, fil) && strnotempty(save)) {    // pas HTML, Θcrire sur disk directement
  970.               int ok=0;
  971.               
  972.               r.is_write=1;    // Θcrire
  973.               if (fexist(fconv(save))) {  // un fichier existe dΘja
  974.                 //if (fsize(fconv(save))==r.size) {  // mΩme taille -- NON tant pis (taille mal declaree)
  975.                 ok=1;    // plus rien α faire
  976.                 filenote(save,NULL);        // noter comme connu
  977.                 file_notify(adr, fil, save, 0, 0, 0);
  978.                 //}
  979.               }
  980.               
  981.               if ((pos<0) && (!ok)) { // Pas de donnΘe en cache et fichier introuvable : erreur!
  982.                 if (opt->norecatch) {
  983.                   file_notify(adr, fil, save, 1, 0, 0);
  984.                   filecreateempty(save);
  985.                   //
  986.                   r.statuscode=STATUSCODE_INVALID;
  987.                   strcpybuff(r.msg,"File deleted by user not recaught");
  988.                   ok=1;     // ne pas rΘcupΘrer (et pas d'erreur)
  989.                 } else {
  990.                   r.statuscode=STATUSCODE_INVALID;
  991.                   strcpybuff(r.msg,"Previous cache file not found");
  992.                   ok=1;    // ne pas rΘcupΘrer
  993.                 }
  994.               }
  995.               
  996.               if (!ok) {  
  997.                 r.out=filecreate(save);
  998. #if HDEBUG
  999.                 printf("direct-disk: %s\n",save);
  1000. #endif
  1001.                 if (r.out!=NULL) {
  1002.                   char BIGSTK buff[32768+4];
  1003.                   LLint size = r.size;
  1004.                   if (size > 0) {
  1005.                     INTsys nl;
  1006.                     do {
  1007.                       nl=fread(buff,1,(INTsys) minimum(size,32768),cache->olddat);
  1008.                       if (nl>0) {
  1009.                         size-=nl; 
  1010.                         if ((INTsys)fwrite(buff,1,(INTsys)nl,r.out)!=nl) {  // erreur
  1011.                           r.statuscode=STATUSCODE_INVALID;
  1012.                           strcpybuff(r.msg,"Cache Read Error : Read To Disk");
  1013.                         }
  1014.                       }
  1015.                     } while((nl>0) && (size>0) && (r.statuscode!=-1));
  1016.                   }
  1017.                   
  1018.                   fclose(r.out);
  1019.                   r.out=NULL;
  1020. #if HTS_WIN==0
  1021.                   chmod(save,HTS_ACCESS_FILE);      
  1022. #endif          
  1023.                 } else {
  1024.                   r.statuscode=STATUSCODE_INVALID;
  1025.                   strcpybuff(r.msg,"Cache Write Error : Unable to Create File");
  1026.                   //printf("%s\n",save);
  1027.                 }
  1028.               }
  1029.               
  1030.             } else
  1031. #endif
  1032.             { // lire en mΘmoire
  1033.               
  1034.               if (pos<0) {
  1035.                 if (strnotempty(save)) { // Pas de donnΘe en cache, bizarre car html!!!
  1036.                   r.statuscode=STATUSCODE_INVALID;
  1037.                   strcpybuff(r.msg,"Previous cache file not found (2)");
  1038.                 } else {                 /* Read in memory from cache */
  1039.                   if (strnotempty(return_save) && fexist(return_save)) {
  1040.                     FILE* fp = fopen(fconv(return_save), "rb");
  1041.                     if (fp != NULL) {
  1042.                       r.adr=(char*) malloct((INTsys)r.size + 4);
  1043.                       if (r.adr != NULL) {
  1044.                         if (r.size > 0 && fread(r.adr, 1, (INTsys) r.size, fp) != r.size) {
  1045.                           r.statuscode=STATUSCODE_INVALID;
  1046.                           strcpybuff(r.msg,"Read error in cache disk data");
  1047.                         }
  1048.                       } else {
  1049.                         r.statuscode=STATUSCODE_INVALID;
  1050.                         strcpybuff(r.msg,"Read error (memory exhausted) from cache");
  1051.                       }
  1052.                       fclose(fp);
  1053.                     }
  1054.                   } else {
  1055.                     r.statuscode=STATUSCODE_INVALID;
  1056.                     strcpybuff(r.msg,"Cache file not found on disk");
  1057.                   }
  1058.                 }
  1059.               } else {
  1060.                 // lire fichier (d'un coup)
  1061.                 r.adr=(char*) malloct((INTsys)r.size+4);
  1062.                 if (r.adr!=NULL) {
  1063.                   if (fread(r.adr,1,(INTsys)r.size,cache->olddat)!=r.size) {  // erreur
  1064.                     freet(r.adr);
  1065.                     r.adr=NULL;
  1066.                     r.statuscode=STATUSCODE_INVALID;
  1067.                     strcpybuff(r.msg,"Cache Read Error : Read Data");
  1068.                   } else
  1069.                     *(r.adr+r.size)='\0';
  1070.                   //printf(">%s status %d\n",back[p].r.contenttype,back[p].r.statuscode);
  1071.                 } else {  // erreur
  1072.                   r.statuscode=STATUSCODE_INVALID;
  1073.                   strcpybuff(r.msg,"Cache Memory Error");
  1074.                 }
  1075.               }
  1076.             }
  1077.           }    // si save==null, ne rien charger (juste en tΩte)
  1078.         } else {
  1079. #if DEBUGCA
  1080.           printf("Cache Read Error : Bad Data");
  1081. #endif
  1082.           r.statuscode=STATUSCODE_INVALID;
  1083.           strcpybuff(r.msg,"Cache Read Error : Bad Data");
  1084.         }
  1085.       } else {  // erreur
  1086. #if DEBUGCA
  1087.         printf("Cache Read Error : Read Header");
  1088. #endif
  1089.         r.statuscode=STATUSCODE_INVALID;
  1090.         strcpybuff(r.msg,"Cache Read Error : Read Header");
  1091.       }
  1092.     } else {
  1093. #if DEBUGCA
  1094.       printf("Cache Read Error : Seek Failed");
  1095. #endif
  1096.       r.statuscode=STATUSCODE_INVALID;
  1097.       strcpybuff(r.msg,"Cache Read Error : Seek Failed");
  1098.     }
  1099.   } else {
  1100. #if DEBUGCA
  1101.     printf("File Cache Not Found");
  1102. #endif
  1103.     r.statuscode=STATUSCODE_INVALID;
  1104.     strcpybuff(r.msg,"File Cache Entry Not Found");
  1105.   }
  1106.   if (!location) {   /* don't export internal buffer */
  1107.     r.location = NULL;
  1108.   }
  1109.   return r;
  1110. }
  1111.  
  1112. /* write (string1-string2)-data in cache */
  1113. /* 0 if failed */
  1114. int cache_writedata(FILE* cache_ndx,FILE* cache_dat,char* str1,char* str2,char* outbuff,int len) {
  1115.   if (cache_dat) {
  1116.     char BIGSTK buff[HTS_URLMAXSIZE*4];
  1117.     char s[256];
  1118.     int pos;
  1119.     fflush(cache_dat); fflush(cache_ndx);
  1120.     pos=ftell(cache_dat);
  1121.     /* first write data */
  1122.     if (cache_wint(cache_dat,len)!=-1) {       // length
  1123.       if ((INTsys)fwrite(outbuff,1,(INTsys)len,cache_dat) == (INTsys) len) {   // data
  1124.         /* then write index */
  1125.         sprintf(s,"%d\n",pos);
  1126.         buff[0]='\0'; strcatbuff(buff,str1); strcatbuff(buff,"\n"); strcatbuff(buff,str2); strcatbuff(buff,"\n");
  1127.         cache_wstr(cache_ndx,buff);
  1128.         if (fwrite(s,1,(INTsys)strlen(s),cache_ndx) == strlen(s)) {
  1129.           fflush(cache_dat); fflush(cache_ndx);
  1130.           return 1;
  1131.         }
  1132.       }
  1133.     }
  1134.   }
  1135.   return 0;
  1136. }
  1137.  
  1138. /* read the data corresponding to (string1-string2) in cache */
  1139. /* 0 if failed */
  1140. int cache_readdata(cache_back* cache,char* str1,char* str2,char** inbuff,int* inlen) {
  1141. #if HTS_FAST_CACHE
  1142.   if (cache->hashtable) {
  1143.     char BIGSTK buff[HTS_URLMAXSIZE*4];
  1144.     long int pos;
  1145.     strcpybuff(buff,str1); strcatbuff(buff,str2);
  1146.     if (inthash_read((inthash)cache->hashtable,buff,(long int*)&pos)) {
  1147.       if (fseek(cache->olddat,((pos>0)?pos:(-pos)),SEEK_SET) == 0) {
  1148.         INTsys len;
  1149.         cache_rint(cache->olddat,&len);
  1150.         if (len>0) {
  1151.           char* mem_buff=(char*)malloct(len+4);    /* Plus byte 0 */
  1152.           if (mem_buff) {
  1153.             if ((INTsys)fread(mem_buff,1,len,cache->olddat)==len) { // lire tout (y compris statuscode etc)*/
  1154.               *inbuff=mem_buff;
  1155.               *inlen=len;
  1156.               return 1;
  1157.             } else
  1158.               freet(mem_buff);
  1159.           }
  1160.         }
  1161.       }
  1162.     }
  1163.   }
  1164. #endif
  1165.   *inbuff=NULL;
  1166.   *inlen=0;
  1167.   return 0;
  1168. }
  1169.  
  1170. // renvoyer uniquement en tΩte, ou NULL si erreur
  1171. // return NULL upon error, and set -1 to r.statuscode
  1172. htsblk* cache_header(httrackp* opt,cache_back* cache,char* adr,char* fil,htsblk* r) {
  1173.   *r=cache_read(opt,cache,adr,fil,NULL,NULL);              // test uniquement
  1174.   if (r->statuscode != -1)
  1175.     return r;
  1176.   else
  1177.     return NULL;
  1178. }
  1179.  
  1180.  
  1181. // Initialisation du cache: crΘer nouveau, renomer ancien, charger..
  1182. void cache_init(cache_back* cache,httrackp* opt) {
  1183.   // ---
  1184.   // utilisation du cache: renommer ancien Θventuel et charger index
  1185.   if (opt->cache) {
  1186. #if DEBUGCA
  1187.     printf("cache init: ");
  1188. #endif
  1189.     if (!cache->ro) {
  1190. #if HTS_WIN
  1191.       mkdir(fconcat(opt->path_log,"hts-cache"));
  1192. #else
  1193.       mkdir(fconcat(opt->path_log,"hts-cache"),HTS_PROTECT_FOLDER);
  1194. #endif
  1195.       if ((fexist(fconcat(opt->path_log,"hts-cache/new.zip")))) {  // il existe dΘja un cache prΘcΘdent.. renommer
  1196.         /* Previous cache from the previous cache version */
  1197. #if 0
  1198.         /* No.. reuse with old httrack releases! */
  1199.         if (fexist(fconcat(opt->path_log,"hts-cache/old.dat")))
  1200.           remove(fconcat(opt->path_log,"hts-cache/old.dat"));
  1201.         if (fexist(fconcat(opt->path_log,"hts-cache/old.ndx")))
  1202.           remove(fconcat(opt->path_log,"hts-cache/old.ndx"));
  1203. #endif
  1204.         /* Previous cache version */
  1205.         if ((fexist(fconcat(opt->path_log,"hts-cache/new.dat"))) && (fexist(fconcat(opt->path_log,"hts-cache/new.ndx")))) {  // il existe dΘja un cache prΘcΘdent.. renommer
  1206.           rename(fconcat(opt->path_log,"hts-cache/new.dat"),fconcat(opt->path_log,"hts-cache/old.dat"));
  1207.           rename(fconcat(opt->path_log,"hts-cache/new.ndx"),fconcat(opt->path_log,"hts-cache/old.ndx"));
  1208.         }
  1209.  
  1210.         /* Remove OLD cache */
  1211.         if (fexist(fconcat(opt->path_log,"hts-cache/old.zip")))
  1212.           remove(fconcat(opt->path_log,"hts-cache/old.zip"));
  1213.         
  1214.         /* Rename */
  1215.         rename(fconcat(opt->path_log,"hts-cache/new.zip"),fconcat(opt->path_log,"hts-cache/old.zip"));
  1216.       }
  1217.       else if ((fexist(fconcat(opt->path_log,"hts-cache/new.dat"))) && (fexist(fconcat(opt->path_log,"hts-cache/new.ndx")))) {  // il existe dΘja un cache prΘcΘdent.. renommer
  1218. #if DEBUGCA
  1219.         printf("work with former cache\n");
  1220. #endif
  1221.         if (fexist(fconcat(opt->path_log,"hts-cache/old.dat")))
  1222.           remove(fconcat(opt->path_log,"hts-cache/old.dat"));
  1223.         if (fexist(fconcat(opt->path_log,"hts-cache/old.ndx")))
  1224.           remove(fconcat(opt->path_log,"hts-cache/old.ndx"));
  1225.         
  1226.         rename(fconcat(opt->path_log,"hts-cache/new.dat"),fconcat(opt->path_log,"hts-cache/old.dat"));
  1227.         rename(fconcat(opt->path_log,"hts-cache/new.ndx"),fconcat(opt->path_log,"hts-cache/old.ndx"));
  1228.       } else {  // un des deux (ou les deux) fichiers cache absents: effacer l'autre Θventuel
  1229. #if DEBUGCA
  1230.         printf("new cache\n");
  1231. #endif
  1232.         if (fexist(fconcat(opt->path_log,"hts-cache/new.dat")))
  1233.           remove(fconcat(opt->path_log,"hts-cache/new.dat"));
  1234.         if (fexist(fconcat(opt->path_log,"hts-cache/new.ndx")))
  1235.           remove(fconcat(opt->path_log,"hts-cache/new.ndx"));
  1236.       }
  1237.     }
  1238.     
  1239.     // charger index cache prΘcΘdent
  1240.     if (
  1241.       (
  1242.       !cache->ro &&
  1243.       fsize(fconcat(opt->path_log,"hts-cache/old.zip")) > 0 
  1244.       )
  1245.       ||
  1246.       (
  1247.       cache->ro &&
  1248.       fsize(fconcat(opt->path_log,"hts-cache/new.zip")) > 0
  1249.       )
  1250.       ) 
  1251.     {
  1252.       if (!cache->ro) {
  1253.         cache->zipInput = unzOpen(fconcat(opt->path_log,"hts-cache/old.zip"));
  1254.       } else {
  1255.         cache->zipInput = unzOpen(fconcat(opt->path_log,"hts-cache/new.zip"));
  1256.       }
  1257.       
  1258.       // Corrupted ZIP file ? Try to repair!
  1259.       if (cache->zipInput == NULL && !cache->ro) {
  1260.           char* name;
  1261.           uLong repaired = 0;
  1262.           uLong repairedBytes = 0;
  1263.           if (!cache->ro) {
  1264.             name = fconcat(opt->path_log,"hts-cache/old.zip");
  1265.           } else {
  1266.             name = fconcat(opt->path_log,"hts-cache/new.zip");
  1267.           }
  1268.           if (opt->log) {
  1269.             fspc(opt->log,"warning"); fprintf(opt->log,"Cache: damaged cache, trying to repair"LF);
  1270.             fflush(opt->log);
  1271.           }
  1272.           if (unzRepair(name, 
  1273.             fconcat(opt->path_log,"hts-cache/repair.zip"),
  1274.             fconcat(opt->path_log,"hts-cache/repair.tmp"),
  1275.             &repaired, &repairedBytes
  1276.             ) == Z_OK) {
  1277.             unlink(name);
  1278.             rename(fconcat(opt->path_log,"hts-cache/repair.zip"), name);
  1279.             cache->zipInput = unzOpen(name);
  1280.             if (opt->log) {
  1281.               fspc(opt->log,"warning"); fprintf(opt->log,"Cache: %d bytes successfully recovered in %d entries"LF, 
  1282.                 (int) repairedBytes, (int) repaired);
  1283.               fflush(opt->log);
  1284.             }
  1285.           } else {
  1286.             if (opt->log) {
  1287.               fspc(opt->log,"warning"); fprintf(opt->log,"Cache: could not repair the cache"LF);
  1288.               fflush(opt->log);
  1289.             }
  1290.           }
  1291.       }
  1292.       
  1293.       // Opened ?
  1294.       if (cache->zipInput!=NULL) {
  1295.         
  1296.         /* Ready directory entries */
  1297.         if (unzGoToFirstFile((unzFile) cache->zipInput) == Z_OK) {
  1298.           char comment[128];
  1299.           char BIGSTK filename[HTS_URLMAXSIZE * 4];
  1300.           int entries = 0;
  1301.           memset(comment, 0, sizeof(comment));       // for truncated reads
  1302.           do  {
  1303.             int readSizeHeader = 0;
  1304.             filename[0] = '\0';
  1305.             comment[0] = '\0';
  1306.             if (unzOpenCurrentFile((unzFile) cache->zipInput) == Z_OK) {
  1307.               if (
  1308.                 (readSizeHeader = unzGetLocalExtrafield((unzFile) cache->zipInput, comment, sizeof(comment) - 2)) > 0
  1309.                 &&
  1310.                 unzGetCurrentFileInfo((unzFile) cache->zipInput, NULL, filename, sizeof(filename) - 2, NULL, 0, NULL, 0) == Z_OK
  1311.                 ) 
  1312.               {
  1313.                 long int pos = (long int) unzGetOffset((unzFile) cache->zipInput);
  1314.                 assertf(readSizeHeader < sizeof(comment));
  1315.                 comment[readSizeHeader] = '\0';
  1316.                 entries++;
  1317.                 if (pos > 0) {
  1318.                   int dataincache = 0;    // data in cache ?
  1319.                   char* filenameIndex = filename;
  1320.                   if (strfield(filenameIndex, "http://")) {
  1321.                     filenameIndex += 7;
  1322.                   }
  1323.                   if (comment[0] != '\0') {
  1324.                     int maxLine = 2;
  1325.                     char* a = comment;
  1326.                     while(*a && maxLine-- > 0) {      // parse only few first lines
  1327.                       char BIGSTK line[1024];
  1328.                       line[0] = '\0';
  1329.                       a+=binput(a, line, sizeof(line) - 2);
  1330.                       if (strfield(line, "X-In-Cache:")) {
  1331.                         if (strfield2(line, "X-In-Cache: 1")) {
  1332.                           dataincache = 1;
  1333.                         } else {
  1334.                           dataincache = 0;
  1335.                         }
  1336.                         break;
  1337.                       }
  1338.                     }
  1339.                   }
  1340.                   if (dataincache)
  1341.                     inthash_add((inthash)cache->hashtable, filenameIndex, pos);
  1342.                   else
  1343.                     inthash_add((inthash)cache->hashtable, filenameIndex, -pos);
  1344.                 } else {
  1345.                   if (opt->log!=NULL) {
  1346.                     fspc(opt->log,"warning"); fprintf(opt->log,"Corrupted cache meta entry #%d"LF, (int)entries);
  1347.                   }
  1348.                 }
  1349.               } else {
  1350.                 if (opt->log!=NULL) {
  1351.                   fspc(opt->log,"warning"); fprintf(opt->log,"Corrupted cache entry #%d"LF, (int)entries);
  1352.                 }
  1353.               }
  1354.               unzCloseCurrentFile((unzFile) cache->zipInput);
  1355.             } else {
  1356.               if (opt->log!=NULL) {
  1357.                 fspc(opt->log,"warning"); fprintf(opt->log,"Corrupted cache entry #%d"LF, (int)entries);
  1358.               }
  1359.             }
  1360.           } while( unzGoToNextFile((unzFile) cache->zipInput) == Z_OK );
  1361.           if ((opt->debug>0) && (opt->log!=NULL)) {
  1362.             fspc(opt->log,"debug"); fprintf(opt->log,"Cache index loaded: %d entries loaded"LF, (int)entries);
  1363.           }
  1364.           opt->is_update=1;        // signaler comme update
  1365.           
  1366.         }    
  1367.         
  1368.       }
  1369.       
  1370.     } else if (
  1371.       (
  1372.       !cache->ro &&
  1373.       fsize(fconcat(opt->path_log,"hts-cache/old.dat")) >=0 && fsize(fconcat(opt->path_log,"hts-cache/old.ndx")) >0
  1374.       )
  1375.       ||
  1376.       (
  1377.       cache->ro &&
  1378.       fsize(fconcat(opt->path_log,"hts-cache/new.dat")) >=0 && fsize(fconcat(opt->path_log,"hts-cache/new.ndx")) > 0
  1379.       )
  1380.       ) {
  1381.       FILE* oldndx=NULL;
  1382. #if DEBUGCA
  1383.       printf("..load cache\n");
  1384. #endif
  1385.       if (!cache->ro) {
  1386.         cache->olddat=fopen(fconcat(opt->path_log,"hts-cache/old.dat"),"rb");        
  1387.         oldndx=fopen(fconcat(opt->path_log,"hts-cache/old.ndx"),"rb");        
  1388.       } else {
  1389.         cache->olddat=fopen(fconcat(opt->path_log,"hts-cache/new.dat"),"rb");        
  1390.         oldndx=fopen(fconcat(opt->path_log,"hts-cache/new.ndx"),"rb");        
  1391.       }
  1392.       // les deux doivent Ωtre ouvrables
  1393.       if ((cache->olddat==NULL) && (oldndx!=NULL)) {
  1394.         fclose(oldndx);
  1395.         oldndx=NULL;
  1396.       }
  1397.       if ((cache->olddat!=NULL) && (oldndx==NULL)) {
  1398.         fclose(cache->olddat);
  1399.         cache->olddat=NULL;
  1400.       }
  1401.       // lire index
  1402.       if (oldndx!=NULL) {
  1403.         int buffl;
  1404.         fclose(oldndx); oldndx=NULL;
  1405.         // lire ndx, et lastmodified
  1406.         if (!cache->ro) {
  1407.           buffl=fsize(fconcat(opt->path_log,"hts-cache/old.ndx"));
  1408.           cache->use=readfile(fconcat(opt->path_log,"hts-cache/old.ndx"));
  1409.         } else {
  1410.           buffl=fsize(fconcat(opt->path_log,"hts-cache/new.ndx"));
  1411.           cache->use=readfile(fconcat(opt->path_log,"hts-cache/new.ndx"));
  1412.         }
  1413.         if (cache->use!=NULL) {
  1414.           char firstline[256];
  1415.           char* a=cache->use;
  1416.           a+=cache_brstr(a,firstline);
  1417.           if (strncmp(firstline,"CACHE-",6)==0) {       // Nouvelle version du cache
  1418.             if (strncmp(firstline,"CACHE-1.",8)==0) {      // Version 1.1x
  1419.               cache->version=(int)(firstline[8]-'0');           // cache 1.x
  1420.               if (cache->version <= 5) {
  1421.                 a+=cache_brstr(a,firstline);
  1422.                 strcpybuff(cache->lastmodified,firstline);
  1423.               } else {
  1424.                 if (opt->errlog) {
  1425.                   fspc(opt->errlog,"error"); fprintf(opt->errlog,"Cache: version 1.%d not supported, ignoring current cache"LF,cache->version);
  1426.                   fflush(opt->errlog);
  1427.                 }
  1428.                 fclose(cache->olddat);
  1429.                 cache->olddat=NULL;
  1430.                 freet(cache->use);
  1431.                 cache->use=NULL;
  1432.               }
  1433.             } else {        // non supportΘ
  1434.               if (opt->errlog) {
  1435.                 fspc(opt->errlog,"error"); fprintf(opt->errlog,"Cache: %s not supported, ignoring current cache"LF,firstline);
  1436.                 fflush(opt->errlog);
  1437.               }
  1438.               fclose(cache->olddat);
  1439.               cache->olddat=NULL;
  1440.               freet(cache->use);
  1441.               cache->use=NULL;
  1442.             }
  1443.             /* */
  1444.           } else {              // Vieille version du cache
  1445.             /* */
  1446.             if (opt->log) {
  1447.               fspc(opt->log,"warning"); fprintf(opt->log,"Cache: importing old cache format"LF);
  1448.               fflush(opt->log);
  1449.             }
  1450.             cache->version=0;        // cache 1.0
  1451.             strcpybuff(cache->lastmodified,firstline); 
  1452.           }
  1453.           opt->is_update=1;        // signaler comme update
  1454.           
  1455.           /* Create hash table for the cache (MUCH FASTER!) */
  1456. #if HTS_FAST_CACHE
  1457.           if (cache->use) {
  1458.             char BIGSTK line[HTS_URLMAXSIZE*2];
  1459.             char linepos[256];
  1460.             int  pos;
  1461.             while ( (a!=NULL) && (a < (cache->use+buffl) ) ) {
  1462.               a=strchr(a+1,'\n');     /* start of line */
  1463.               if (a) {
  1464.                 a++;
  1465.                 /* read "host/file" */
  1466.                 a+=binput(a,line,HTS_URLMAXSIZE);
  1467.                 a+=binput(a,line+strlen(line),HTS_URLMAXSIZE);
  1468.                 /* read position */
  1469.                 a+=binput(a,linepos,200);
  1470.                 sscanf(linepos,"%d",&pos);
  1471.                 inthash_add((inthash)cache->hashtable,line,pos);
  1472.               }
  1473.             }
  1474.             /* Not needed anymore! */
  1475.             freet(cache->use);
  1476.             cache->use=NULL;
  1477.           }
  1478. #endif
  1479.         }
  1480.       }
  1481.       }  // taille cache>0
  1482.       
  1483. #if DEBUGCA
  1484.       printf("..create cache\n");
  1485. #endif
  1486.       if (!cache->ro) {
  1487.         // ouvrir caches actuels
  1488.         structcheck(fconcat(opt->path_log, "hts-cache/"));
  1489.         
  1490.         if (1) {
  1491.           /* Create ZIP file cache */
  1492.           cache->zipOutput = (void*) zipOpen(fconcat(opt->path_log,"hts-cache/new.zip"), 0);
  1493.  
  1494.           if (cache->zipOutput != NULL) {
  1495.             // supprimer old.lst
  1496.             if (fexist(fconcat(opt->path_log,"hts-cache/old.lst")))
  1497.               remove(fconcat(opt->path_log,"hts-cache/old.lst"));
  1498.             // renommer
  1499.             if (fexist(fconcat(opt->path_log,"hts-cache/new.lst")))
  1500.               rename(fconcat(opt->path_log,"hts-cache/new.lst"),fconcat(opt->path_log,"hts-cache/old.lst"));
  1501.             // ouvrir
  1502.             cache->lst=fopen(fconcat(opt->path_log,"hts-cache/new.lst"),"wb");
  1503.             {
  1504.               filecreate_params tmp;
  1505.               strcpybuff(tmp.path,opt->path_html);    // chemin
  1506.               tmp.lst=cache->lst;                 // fichier lst
  1507.               filenote("",&tmp);        // initialiser filecreate
  1508.             }
  1509.             
  1510.             // supprimer old.txt
  1511.             if (fexist(fconcat(opt->path_log,"hts-cache/old.txt")))
  1512.               remove(fconcat(opt->path_log,"hts-cache/old.txt"));
  1513.             // renommer
  1514.             if (fexist(fconcat(opt->path_log,"hts-cache/new.txt")))
  1515.               rename(fconcat(opt->path_log,"hts-cache/new.txt"),fconcat(opt->path_log,"hts-cache/old.txt"));
  1516.             // ouvrir
  1517.             cache->txt=fopen(fconcat(opt->path_log,"hts-cache/new.txt"),"wb");
  1518.             if (cache->txt) {
  1519.               fprintf(cache->txt,"date\tsize'/'remotesize\tflags(request:Update,Range state:File response:Modified,Chunked,gZipped)\t");
  1520.               fprintf(cache->txt,"statuscode\tstatus ('servermsg')\tMIME\tEtag|Date\tURL\tlocalfile\t(from URL)"LF);
  1521.             }
  1522.           }
  1523.         } else {
  1524.           cache->dat=fopen(fconcat(opt->path_log,"hts-cache/new.dat"),"wb");        
  1525.           cache->ndx=fopen(fconcat(opt->path_log,"hts-cache/new.ndx"),"wb");        
  1526.           // les deux doivent Ωtre ouvrables
  1527.           if ((cache->dat==NULL) && (cache->ndx!=NULL)) {
  1528.             fclose(cache->ndx);
  1529.             cache->ndx=NULL;
  1530.           }
  1531.           if ((cache->dat!=NULL) && (cache->ndx==NULL)) {
  1532.             fclose(cache->dat);
  1533.             cache->dat=NULL;
  1534.           }
  1535.           
  1536.           if (cache->ndx!=NULL) {
  1537.             char s[256];
  1538.             
  1539.             cache_wstr(cache->dat,"CACHE-1.5");
  1540.             fflush(cache->dat);
  1541.             cache_wstr(cache->ndx,"CACHE-1.5");
  1542.             fflush(cache->ndx);
  1543.             //
  1544.             time_gmt_rfc822(s);   // date et heure actuelle GMT pour If-Modified-Since..
  1545.             cache_wstr(cache->ndx,s);        
  1546.             fflush(cache->ndx);    // un petit fflush au cas o∙
  1547.             
  1548.             // supprimer old.lst
  1549.             if (fexist(fconcat(opt->path_log,"hts-cache/old.lst")))
  1550.               remove(fconcat(opt->path_log,"hts-cache/old.lst"));
  1551.             // renommer
  1552.             if (fexist(fconcat(opt->path_log,"hts-cache/new.lst")))
  1553.               rename(fconcat(opt->path_log,"hts-cache/new.lst"),fconcat(opt->path_log,"hts-cache/old.lst"));
  1554.             // ouvrir
  1555.             cache->lst=fopen(fconcat(opt->path_log,"hts-cache/new.lst"),"wb");
  1556.             {
  1557.               filecreate_params tmp;
  1558.               strcpybuff(tmp.path,opt->path_html);    // chemin
  1559.               tmp.lst=cache->lst;                 // fichier lst
  1560.               filenote("",&tmp);        // initialiser filecreate
  1561.             }
  1562.             
  1563.             // supprimer old.txt
  1564.             if (fexist(fconcat(opt->path_log,"hts-cache/old.txt")))
  1565.               remove(fconcat(opt->path_log,"hts-cache/old.txt"));
  1566.             // renommer
  1567.             if (fexist(fconcat(opt->path_log,"hts-cache/new.txt")))
  1568.               rename(fconcat(opt->path_log,"hts-cache/new.txt"),fconcat(opt->path_log,"hts-cache/old.txt"));
  1569.             // ouvrir
  1570.             cache->txt=fopen(fconcat(opt->path_log,"hts-cache/new.txt"),"wb");
  1571.             if (cache->txt) {
  1572.               fprintf(cache->txt,"date\tsize'/'remotesize\tflags(request:Update,Range state:File response:Modified,Chunked,gZipped)\t");
  1573.               fprintf(cache->txt,"statuscode\tstatus ('servermsg')\tMIME\tEtag|Date\tURL\tlocalfile\t(from URL)"LF);
  1574.             }
  1575.             
  1576.             // test
  1577.             // cache_writedata(cache->ndx,cache->dat,"//[TEST]//","test1","TEST PIPO",9);
  1578.           }
  1579.         }
  1580.         
  1581.       } else {
  1582.         cache->lst = cache->dat = cache->ndx = NULL;
  1583.       }
  1584.       
  1585.   }
  1586.   
  1587. }
  1588.  
  1589.  
  1590.  
  1591.  
  1592. // lire un fichier.. (compatible \0)
  1593. char* readfile(char* fil) {
  1594.   return readfile2(fil, NULL);
  1595. }
  1596.  
  1597. char* readfile2(char* fil, LLint* size) {
  1598.   char* adr=NULL;
  1599.   INTsys len=0;
  1600.   len=fsize(fil);
  1601.   if (len >= 0) {  // exists
  1602.     FILE* fp;
  1603.     fp=fopen(fconv(fil),"rb");
  1604.     if (fp!=NULL) {  // n'existe pas (!)
  1605.       adr=(char*) malloct(len+1);
  1606.       if (size != NULL)
  1607.         *size = len;
  1608.       if (adr!=NULL) {
  1609.         if (len > 0 && (INTsys)fread(adr,1,len,fp) != len) {    // fichier endommagΘ ?
  1610.           freet(adr);
  1611.           adr=NULL;
  1612.         } else
  1613.           *(adr+len)='\0';
  1614.       }
  1615.       fclose(fp);
  1616.     }
  1617.   }
  1618.   return adr;
  1619. }
  1620.  
  1621. char* readfile_or(char* fil,char* defaultdata) {
  1622.   char* realfile=fil;
  1623.   char* ret;
  1624.   if (!fexist(fil))
  1625.     realfile=fconcat(hts_rootdir(NULL),fil);
  1626.   ret=readfile(realfile);
  1627.   if (ret)
  1628.     return ret;
  1629.   else {
  1630.     char *adr=malloct(strlen(defaultdata)+2);
  1631.     if (adr) {
  1632.       strcpybuff(adr,defaultdata);
  1633.       return adr;
  1634.     }
  1635.   }
  1636.   return NULL;
  1637. }
  1638.  
  1639. // Θcriture/lecture d'une chaεne sur un fichier
  1640. // -1 : erreur, sinon 0
  1641. int cache_wstr(FILE* fp,char* s) {
  1642.   INTsys i;
  1643.   char buff[256+4];
  1644.   i = s != NULL ? strlen(s) : 0;
  1645.   sprintf(buff,INTsysP "\n",i);
  1646.   if (fwrite(buff,1,(INTsys)strlen(buff),fp) != strlen(buff))
  1647.     return -1;
  1648.   if (i > 0 && (INTsys)fwrite(s,1,i,fp) != i)
  1649.     return -1;
  1650.   return 0;
  1651. }
  1652. void cache_rstr(FILE* fp,char* s) {
  1653.   INTsys i;
  1654.   char buff[256+4];
  1655.   linput(fp,buff,256);
  1656.   sscanf(buff,INTsysP,&i);
  1657.   if (i < 0 || i > 32768)    /* error, something nasty happened */
  1658.     i=0;
  1659.   if (i>0) {
  1660.     if ((int) fread(s,1,i,fp) != i) {
  1661.       int fread_cache_failed = 0;
  1662.       assertf(fread_cache_failed);
  1663.     }
  1664.   }
  1665.   *(s+i)='\0';
  1666. }
  1667. char* cache_rstr_addr(FILE* fp) {
  1668.   INTsys i;
  1669.   char* addr = NULL;
  1670.   char buff[256+4];
  1671.   linput(fp,buff,256);
  1672.   sscanf(buff,INTsysP,&i);
  1673.   if (i < 0 || i > 32768)    /* error, something nasty happened */
  1674.     i=0;
  1675.   if (i > 0) {
  1676.     addr = malloct(i + 1);
  1677.     if (addr != NULL) {
  1678.       if ((int) fread(addr,1,i,fp) != i) {
  1679.         int fread_cache_failed = 0;
  1680.         assertf(fread_cache_failed);
  1681.       }
  1682.       *(addr+i)='\0';
  1683.     }
  1684.   }
  1685.   return addr;
  1686. }
  1687. int cache_brstr(char* adr,char* s) {
  1688.   int i;
  1689.   int off;
  1690.   char buff[256+4];
  1691.   off=binput(adr,buff,256);
  1692.   adr+=off;
  1693.   sscanf(buff,"%d",&i);
  1694.   if (i>0)
  1695.     strncpy(s,adr,i);
  1696.   *(s+i)='\0';
  1697.   off+=i;
  1698.   return off;
  1699. }
  1700. int cache_quickbrstr(char* adr,char* s) {
  1701.   int i;
  1702.   int off;
  1703.   char buff[256+4];
  1704.   off=binput(adr,buff,256);
  1705.   adr+=off;
  1706.   sscanf(buff,"%d",&i);
  1707.   if (i>0)
  1708.     strncpy(s,adr,i);
  1709.   *(s+i)='\0';
  1710.   off+=i;
  1711.   return off;
  1712. }
  1713. /* idem, mais en int */
  1714. int cache_brint(char* adr,int* i) {
  1715.   char s[256];
  1716.   int r=cache_brstr(adr,s);
  1717.   if (r!=-1)
  1718.     sscanf(s,"%d",i);
  1719.   return r;
  1720. }
  1721. void cache_rint(FILE* fp,int* i) {
  1722.   char s[256];
  1723.   cache_rstr(fp,s);
  1724.   sscanf(s,"%d",i);
  1725. }
  1726. int cache_wint(FILE* fp,int i) {
  1727.   char s[256];
  1728.   sprintf(s,"%d",(int) i);
  1729.   return cache_wstr(fp,s);
  1730. }
  1731. void cache_rLLint(FILE* fp,LLint* i) {
  1732.   char s[256];
  1733.   cache_rstr(fp,s);
  1734.   sscanf(s,LLintP,i);
  1735. }
  1736. int cache_wLLint(FILE* fp,LLint i) {
  1737.   char s[256];
  1738.   sprintf(s,LLintP,(LLint) i);
  1739.   return cache_wstr(fp,s);
  1740. }
  1741. // -- cache --
  1742.